﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Tao.OpenGl;

using CutAways.Modeling;
using CutAways.Geometry;

namespace CutAways.Illustration
{
	static class OcclusionQuery
	{
		public static int GetPixelCount(Model model, GeometricObject obj, Camera viewpoint)
		{
			return GetPixelCounts(model, new GeometricObject[] { obj }, null, viewpoint)[0];
		}

		public static int[] GetPixelCounts(Model model, GeometricObject[] occludees, GeometricObject[] occluders, Camera viewpoint)
		{
			if (model == null || occludees == null || viewpoint == null)
				return null;

			int[] passingSamples = new int[occludees.Length];
			int[] queryIDs = new int[occludees.Length];

			// ------------------------------------------------------------------

			Gl.glGenQueries(queryIDs.Length, queryIDs);
			
			Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);	// Clear the Screen and the Depth Buffer
			Gl.glLoadIdentity();					                        // reset the current modelview matrix

			Glu.gluLookAt(viewpoint.Eye.X, viewpoint.Eye.Y, viewpoint.Eye.Z, viewpoint.Center.X, viewpoint.Center.Y, viewpoint.Center.Z, viewpoint.Up.X, viewpoint.Up.Y, viewpoint.Up.Z);

			
			foreach (GeometricObject o in occludees) // vykreslim vsechny occludees
				model.DrawObject(o);

			if (occluders != null)
				foreach (GeometricObject o in occluders) // vykreslim vsechny occludery
					model.DrawObject(o);


			Gl.glShadeModel(Gl.GL_FLAT);
			Gl.glDisable(Gl.GL_LIGHTING);
			//Gl.glDisable(Gl.GL_COLOR_MATERIAL);
			Gl.glDisable(Gl.GL_NORMALIZE);
			Gl.glDepthMask(Gl.GL_FALSE);
			Gl.glColorMask(0, 0, 0, 0);
			

			for (int i = 0; i < occludees.Length; i++)
			{
				Gl.glBeginQuery(Gl.GL_SAMPLES_PASSED, queryIDs[i]);
				model.DrawObject(occludees[i]);
				Gl.glEndQuery(Gl.GL_SAMPLES_PASSED);
			}

			

			for (int i = 0; i < occludees.Length; i++)
			{
				int samples;
				Gl.glGetQueryObjectiv(queryIDs[i], Gl.GL_QUERY_RESULT, out samples);
				passingSamples[i] = samples;
			}

			Gl.glDeleteQueries(queryIDs.Length, queryIDs);

			// Restore normal drawing state
			Gl.glShadeModel(Gl.GL_SMOOTH);
			Gl.glEnable(Gl.GL_LIGHTING);
			//Gl.glEnable(Gl.GL_COLOR_MATERIAL);
			Gl.glEnable(Gl.GL_NORMALIZE);
			Gl.glColorMask(1, 1, 1, 1);
			Gl.glDepthMask(Gl.GL_TRUE);
			//Gl.glFlush();
			
			return passingSamples;
		}

	}
}
